
package at.fhj.itm10.ticketmaster.services.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.faces.context.FacesContext;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.naming.NamingException;
import javax.servlet.ServletContext;

import org.apache.log4j.Logger;

import at.fhj.itm10.ticketmaster.beans.SharingBean;
import at.fhj.itm10.ticketmaster.dao.AddressDAO;
import at.fhj.itm10.ticketmaster.dao.CustomerDAO;
import at.fhj.itm10.ticketmaster.dao.DAOException;
import at.fhj.itm10.ticketmaster.entities.Address;
import at.fhj.itm10.ticketmaster.entities.Customer;
import at.fhj.itm10.ticketmaster.helper.MD5HashmakerEmail;
import at.fhj.itm10.ticketmaster.helper.MailHelper;
import at.fhj.itm10.ticketmaster.helper.Validator;
import at.fhj.itm10.ticketmaster.services.CustomerService;
import at.fhj.itm10.ticketmaster.services.ServiceException;

/**
 * {@inheritDoc}
 * 
 * @author Wolfgang Gaar
 * @author Sabrina Gruber
 * @author Tammo Böhme
 * @ Grüner Gabi (impressum)
 */
public class CustomerServiceImpl extends AbstractService implements
CustomerService {

	private String title;
	private String name;

	private String lastName;
	private String userName;
	private String email;
	private String password;
	private String secpassword;
	private boolean gender;
	private long adressId;
	private boolean isPromoter;
	private boolean newsletter;
	private Date birth;
	private Date registerDate;
	private boolean agb;
	private boolean impressum;	

	private Customer customer;
	private Address address;
	private String addressName;
	private String street;
	private String zip;
	private String city;
	private String country;

	private Logger logger = Logger.getLogger(CustomerServiceImpl.class);

	private CustomerDAO dao;

	private AddressDAO addressDao;

	public CustomerDAO getDao() {
		logger.debug("getDao()");
		return dao;
	}

	public void setDao(final CustomerDAO theDao) {
		logger.debug("setDao("+ theDao +")");
		this.dao = theDao;
	}

	public void setAddressDao(final AddressDAO theDao) {
		this.addressDao = theDao;
	}

	public AddressDAO getAddressDao() {
		logger.debug("getAddressDao()");
		return addressDao;
	}

	public void insertCustomer(Customer customer, Address address) {
		logger.debug("insertCustomer()");

		Validator.notNullOrThrow(customer, "customer is null");
		Validator.notNullOrThrow(address, "address is null");
		/*	Validator.zeroOrThrow(customer.getId(),
				"id for new customer must be zero - will be autofilled"); 
		Validator.zeroOrThrow(address.getId(),
				"id for new customer must be zero - will be autofilled"); */

		try {
			begin();

			getAddressDao().insert(address);
			customer.setFkAddressId(address.getId());
			getDao().insert(customer);

			commit();
		} catch (DAOException e) {
			rollback();

			throw new ServiceException("Error on inserting data", e);
		} finally {
			closeConnection();
		}
	}

	public void updateCustomer(Customer customer) {
		logger.debug("updateCustomer()");

		Validator.notNullOrThrow(customer, "customer is null");
		Validator.notZeroOrThrow(customer.getId(), "id must be given for update");

		try {
			begin();
			getDao().update(customer);
			commit();
		} catch (DAOException e) {
			rollback();

			throw new ServiceException("Error on updating data", e);
		} finally {
			closeConnection();
		}
	}

	public void deleteCustomer(Customer customer) {
		logger.debug("deleteCustomer()");

		Validator.notNullOrThrow(customer, "customer is null");
		Validator.notZeroOrThrow(customer.getId(), "id must be given for delete");

		try {
			begin();
			getDao().delete(customer);
			commit();
		} catch (DAOException e) {
			rollback();

			throw new ServiceException("Error on deleting data", e);
		} finally {
			closeConnection();
		}
	}

	public Customer findById(long id) {
		logger.debug("findById()");

		Customer customer = null;
		try {
			begin();
			customer = getDao().findById(id);
			commit();
		} catch (DAOException e) {
			rollback();

			throw new ServiceException("Error on retrieving data", e);
		} finally {
			closeConnection();
		}

		return customer;
	}

	public Customer findByEMail(String email) {
		logger.debug("findByEMail()");

		Validator.notNullOrThrow(email, "email is null");

		Customer customer = null;
		try {
			begin();

			// FIXME: by definition email addresses are unique but the DAO returns a list
			List<Customer> customers = getDao().findByEMail(email);
			if (customers.size() > 0) {
				customer = customers.get(0);
			}

			commit();
		} catch (DAOException e) {
			rollback();

			throw new ServiceException("Error on retrieving data", e);
		} finally {
			closeConnection();
		}

		return customer;
	}

	public Customer findByUsername(String username) {
		logger.debug("findByUsername()");

		Validator.notNullOrThrow(username, "username is null");

		Customer customer = null;
		try {
			begin();

			// FIXME: by definition usernames are unique but the DAO returns a list
			List<Customer> customers = getDao().findByUsername(username);
			if (customers.size() > 0) {
				customer = customers.get(0);
			}

			commit();
		} catch (DAOException e) {
			rollback();

			throw new ServiceException("Error on retrieving data", e);
		} finally {
			closeConnection();
		}

		return customer;
	}

	public List<Customer> findAll() {
		logger.debug("findAll()");

		List<Customer> customers = null;
		try {
			begin();
			customers = getDao().findAll();
			commit();
		} catch (DAOException e) {
			rollback();

			throw new ServiceException("Error on retrieving data", e);
		} finally {
			closeConnection();
		}

		return customers;
	}

	/*
	 * kevin ballach email for activation link
	 * ->oida utf8! ueberarbeitet von martin gritsch fuer password recovery mail
	 */
	public void sendRecoveryMail(String email, String resetKey) throws Exception {
		Session activationMailSession = null;
		try {
			activationMailSession = MailHelper.getSession();
		} catch (NamingException e) {
			throw new ServiceException("", e);
		}

		try {
			MD5HashmakerEmail.generateMD5Code(email);
		} catch (NoSuchAlgorithmException e) {
			throw new ServiceException("", e);
		}

		try {
			Message message = new MimeMessage(activationMailSession);
			//BodyPart messageBodyPart = new MimeBodyPart();

			// email addresse ändern
			message.setFrom(new InternetAddress(activationMailSession
					.getProperty("mail.from")));
			message.setRecipients(Message.RecipientType.TO,
					InternetAddress.parse(email));
			message.setSubject("Password Recovery");

			URL url = new URL("http://localhost:8080/Ticketmaster/resetconfirmation.xhtml?resetKey=" + resetKey + "&email=" + email);
			message.setContent(
					"Passwort zuruecksetzen <br/>"
							+ "Bitte klicken Sie den Link um das Zuruecksetzen Ihres Passworts abzuschliessen! <br/>"
							+ "<br/>"
							+ "<a href=\"" + url + "\">Klick", "text/html");

			Transport.send(message);

			System.out.println("Done");
			System.out.println(email);

			System.out.println(MD5HashmakerEmail.getMd5code());
		} catch (MessagingException e) {
			throw new ServiceException("", e);
		}
	}

	/*
	 * kevin ballach email for activation link
	 */

	public void sendActivationMail(String email) throws Exception {
		Session activationMailSession = null;//before static

		logger.debug("sendActivationMail()");
		logger.info(email);

		try {
			activationMailSession = MailHelper.getSession();
			logger.info("GetSession" + activationMailSession);
		} catch (NamingException e) {
			throw new ServiceException("Sesseion Invalid", e);
		}

		try {
			MD5HashmakerEmail.generateMD5Code(email);
			logger.info("generateMD5Code");
		} catch (NoSuchAlgorithmException e) {
			throw new ServiceException("Algo is not available!", e);
		}

		try {
			Message message = new MimeMessage(activationMailSession);
			//BodyPart messageBodyPart = new MimeBodyPart();
			logger.info("create messagebody");

			// email addresse ändern
			message.setFrom(new InternetAddress(activationMailSession
					.getProperty("mail.from")));
			message.setRecipients(Message.RecipientType.TO,
					InternetAddress.parse(email));
			logger.info("empfänger"+email);
			message.setSubject("Activation");

			URL url = new URL(
					"http://localhost:8080/ticketmaster/activation.xhtml?email="
							+ email + "&hash=" + MD5HashmakerEmail.getMd5code());

			message.setContent(
					"Aktivierungsmail <br/>"
							+ "Bitte klicken Sie den Link um die Aktivierung abzuschließenen! <br/>"
							+ "<br/>"
							+ "<a href=\"" + url + "\">Klick", "text/html");

			Transport.send(message);

			logger.info("Done" + email + MD5HashmakerEmail.getMd5code());
			//System.out.println("Done");
			//System.out.println(email);

			//System.out.println(MD5HashmakerEmail.getMd5code());
		} catch (MessagingException e) {
			throw new ServiceException("Failed to send Email", e);
		}
	}




	public String register() {
		logger.debug("register()");

		Address a = new Address();
		a.setName(this.getAddressName());
		a.setStreet(this.getStreet());
		a.setZip(this.getZip());
		a.setCity(this.getCity());
		a.setCountry(this.getCountry());

		Customer c = new Customer();

		c.setTitle(this.getTitle());
		c.setFirstName(this.getName());
		c.setLastName(this.getLastName());
		c.setUserName(this.getUserName());
		c.setEmail(this.getEmail());
		logger.debug(password);
		try {
			String md5hash = MD5HashmakerEmail.generateMD5Code(password);
			logger.debug("MD5 Hash: " + md5hash);
			c.setPassword(md5hash);
		} catch (NoSuchAlgorithmException e) {
			throw new ServiceException("Algo is not available", e);
		}
		c.setMale(this.getGender());
		c.setNewsletter(this.isNewsletter());
		logger.debug("BirthDate: " +this.getBirth());
		c.setBirthDate(this.getBirth());
		c.setOrganizer(this.getisPromoter());

		c.setRegisterDate(Calendar.getInstance().getTime());
		c.setActivationKey(MD5HashmakerEmail.getMd5code());
		logger.debug("AddressDAO: ---------------------------------------- " + addressDao);
		try {
			
			addressDao.insert(a);
			logger.debug("AdressId: ----------------------------------------- " + a.getId() );
			c.setFkAddressId(a.getId());
			logger.debug("CustomerDao: " + dao);
			dao.insert(c);	

		} catch (DAOException e1) {
			throw new ServiceException("Insert failed", e1);
		}
		//added activation key
		//Kevin ballach
		try {
			sendActivationMail(email);
		} catch (Exception e) {
			throw new ServiceException("sendActivationMail() Error", e);
		}
		
		
		return "registerconfirmation";
	}

	public String getAgbText() {
		logger.debug("getAgbText()");
		ServletContext servletContext = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
		String path = servletContext.getRealPath("/") + "WEB-INF/agb.txt";

		StringBuffer stringBuffer = null;
		BufferedReader bufferedReader = null;
		InputStreamReader sr = null;

		try {
			File file = new File(path);		
			sr = new InputStreamReader(new FileInputStream(file), "UTF8");
			bufferedReader = new BufferedReader(sr);
			stringBuffer = new StringBuffer();
			String line;
			while ((line = bufferedReader.readLine()) != null) {
				stringBuffer.append(line);
				stringBuffer.append("\n");
			}
		} catch (IOException e) {
			throw new ServiceException("", e);
		}
		finally{
			try {
				if(sr != null)
					sr.close();
				if(bufferedReader != null)
					bufferedReader.close();
			} catch (IOException e) {
				throw new ServiceException("", e);
			}
		}


		if(stringBuffer == null){
			String msg = "Bitte wenden Sie sich an unseren Kundenservice.";
			return msg;
		}
		else {
			return stringBuffer.toString();
		}
	}

	public Customer getCustomer() {
		logger.debug("getCustomer()");
		return customer;
	}

	public void setCustomer(Customer customer) {
		logger.debug("setCustomer("+ customer +")");
		this.customer = customer;
	}

	public boolean getisPromoter() {
		logger.debug("getisPromoter()");
		return isPromoter;
	}

	public void setIsPromoter(boolean isPromoter) {
		logger.debug("setIsPromoter("+ isPromoter +")");
		this.isPromoter = isPromoter;
	}
	public String getTitle() {
		logger.debug("getTitle()");
		return title;
	}

	public void setTitle(String title) {
		logger.debug("setTitle("+ title +")");
		this.title = title;
	}

	public String getName() {
		logger.debug("getName()");
		return name;
	}

	public void setName(String name) {
		logger.debug("setName("+ name +")");
		this.name = name;
	}

	public String getLastName() {
		logger.debug("getLastName()");
		return lastName;
	}

	public void setLastName(String lastName) {
		logger.debug("setLastName("+ lastName +")");
		this.lastName = lastName;
	}

	public String getUserName() {
		logger.debug("getUserName()");
		return userName;
	}

	public void setUserName(String userName) {
		logger.debug("setUserName("+ userName +")");
		this.userName = userName;
	}

	public String getEmail() {
		logger.debug("getEmail()");
		return email;
	}

	public void setEmail(String email) {
		logger.debug("setEmail("+ email +")");
		this.email = email;
	}

	public String getPassword() {
		logger.debug("getPassword()");
		return password;
	}

	public void setPassword(String password) {
		logger.debug("setPassword("+ password +")");
		this.password = password;
	}

	public boolean getGender() {
		logger.debug("getGender()");
		return gender;
	}

	public void setGender(boolean gender) {
		logger.debug("setGender("+ gender +")");
		this.gender = gender;
	}

	public long getAdressId() {
		logger.debug("getAdressId()");
		return adressId;
	}

	public void setAdressId(long adressId) {
		logger.debug("setAdressId("+ adressId +")");
		this.adressId = adressId;
	}

	public boolean isNewsletter() {
		logger.debug("isNewsletter()");
		return newsletter;
	}

	public void setNewsletter(boolean newsletter) {
		logger.debug("setNewsletter("+ newsletter +")");
		this.newsletter = newsletter;
	}

	public Date getBirth() {
		logger.debug("getBirth()");
		return birth;
	}

	public void setBirth(Date birth) {
		logger.debug("setBirth("+ birth +")");
		this.birth = birth;
	}

	public String getSecpassword() {
		logger.debug("getSecpassword()");
		return secpassword;
	}

	public void setSecpassword(String secpassword) {
		logger.debug("setSecpassword("+ secpassword +")");
		this.secpassword = secpassword;
	}
	public Address getAddress() {
		logger.debug("getAddress()");
		return address;
	}

	public void setAddress(Address address) {
		logger.debug("setAddress("+ address +")");
		this.address = address;
	}

	public String getAddressName() {
		logger.debug("getAddressName()");
		return addressName;
	}

	public void setAddressName(String addressName) {
		logger.debug("setAddressName("+ addressName +")");
		this.addressName = addressName;
	}

	public String getStreet() {
		logger.debug("getStreet()");
		return street;
	}

	public void setStreet(String street) {
		logger.debug("setStreet("+ street +")");
		this.street = street;
	}

	public String getZip() {
		logger.debug("getZip()");
		return zip;
	}

	public void setZip(String zip) {
		logger.debug("setZip("+ zip +")");
		this.zip = zip;
	}

	public String getCity() {
		logger.debug("getCity()");
		return city;
	}

	public void setCity(String city) {
		logger.debug("setCity("+ city +")");
		this.city = city;
	}

	public String getCountry() {
		logger.debug("getCountry()");
		return country;
	}

	public void setCountry(String country) {
		logger.debug("setCountry("+ country +")");
		this.country = country;
	}

	public Date getRegisterDate() {
		logger.debug("getRegisterDate()");
		return (Date) registerDate.clone();
	}

	public void setRegisterDate(Date registerDate) {
		logger.debug("setRegisterDate("+ registerDate +")");
		this.registerDate = (Date) registerDate.clone();
	}

	public boolean isAgb() {
		logger.debug("isAgb()");
		return agb;
	}

	public void setAgb(boolean agb) {
		logger.debug("setAgb("+ agb +")");
		this.agb = agb;
	}


	public boolean isImpressum() {
		logger.debug("isImpressum()");
		return impressum;
	}

	public void setImpressum(boolean impressum) {
		logger.debug("setImpressum("+ impressum +")");
		this.impressum = impressum;
	}

	public void resetCustomerPasswordByEMail(String email,
			String newPlaintextPassword) {
		logger.debug("resetCustomerPasswordByEMail()");

		try {
			begin();

			Customer customer = findByEMail(email);
			if (customer == null) {
				throw new Exception("customer is null");
			}

			customer.setPassword(MD5HashmakerEmail
					.generateMD5Code(newPlaintextPassword));
			customer.setReset(false);
			customer.setResetKey("");

			updateCustomer(customer);
			commit();
		} catch (Exception e) {
			rollback();

			throw new ServiceException("Error on resetting password", e);
		} finally {
			closeConnection();
		}

	}




	public String getImpressumText() {
		logger.debug("getImpressumText()");

		ServletContext servletContext = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
		String path = servletContext.getRealPath("/") + "WEB-INF/impressum.txt";

		StringBuffer stringBuffer = null;
		BufferedReader bufferedReader = null;
		InputStreamReader sr = null;

		try {
			File file = new File(path);		
			sr = new InputStreamReader(new FileInputStream(file), "UTF8");
			bufferedReader = new BufferedReader(sr);
			stringBuffer = new StringBuffer();
			String line;
			while ((line = bufferedReader.readLine()) != null) {
				stringBuffer.append(line);
				stringBuffer.append("\n");
			}
		} catch (IOException e) {
			throw new ServiceException("", e);
		}
		finally{
			try {
				if(sr != null)
					sr.close();
				if(bufferedReader != null)
					bufferedReader.close();
			} catch (IOException e) {
				throw new ServiceException("", e);
			}
		}


		if(stringBuffer == null){
			String msg = "Bitte wenden Sie sich an unseren Kundenservice.";
			return msg;
		}
		else {
			return stringBuffer.toString();
		}
	}
	

}
